home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Shareware Grab Bag
/
Shareware Grab Bag.iso
/
090
/
yase.arc
/
PRINTF.ASM
< prev
next >
Wrap
Assembly Source File
|
1986-12-13
|
10KB
|
281 lines
******************************************************************
* COPYRIGHT (C) 1986 by Donald Krantz and James Stanley
* - Note: This is a real, live, actual, registered copyright,
* and should be treated as such. This source code is from
* the book "68000 Assembly Language", Krantz and Stanley,
* Addison-Wesley Publishing Company, Reading, MA, 1986.
*
* Permission granted by the authors for non-commercial use
* in programs released to the public domain, as long as this
* copyright notice remains attached and visible.
*
*****************************************************************
* PRINTF - subset/superset of C printf standard I/O function
* Control args:
*
* push last parameter in control string first, then next-to
* last, etc. Push address of control string last.
*
* %d: print signed decimal word
* %u: print unsigned decimal word
* %D: print signed decimal longword
* %U: print unsigned decimal longword
* %x: print hexadecimal word
* %X: print hexadecimal longword
* %s: print null terminated string
* %c: print character
* %v: cursor (x,y) - push Y, then X, as words.
* %default: print next character as literal
*****************************************************************
xdef printf
xref case,putc,cursor
*****************************************************************
* Local variable displacement definitions
leftj equ -2 * left justify displacement
field equ -4 * field width displacement
signf equ -6 * sign flag
*****************************************************************
printf:
link a6,#-6 * make 2 (word) local vars
movem.l d0-d6/a0-a2,-(a7)
move.l 8(a6),a1 * get control string address
lea 12(a6),a2 * get pointer to parameters
loop:
move.b (a1)+,d0 * get control string character
beq exit * quit if it's a null.
ext.w d0 * clear high byte
cmp.b #'%',d0 * see if it's control flag
bne no_ctl * branch if not
clr.w leftj(a6) * clear left justify flag
clr.w field(a6) * clear field width
clr.w signf(a6) * clear sign flag
lp0pf:
move.b (a1)+,d0 * get control string character
ext.w d0 * clear high byte
cmp.b #'-',d0 * is it minus?
bne sk0pf * no, keep going
move.w #1,leftj(a6) * set left justify flag
bra lp0pf * try for next char
sk0pf:
cmp.b #'0',d0 * is it smaller than a digit?
blt sk1pf * yes, continue processing
cmp.b #'9',d0 * is it larger than a digit?
bgt sk1pf * yes, continue processing
move.w field(a6),d1 * get current field size
mulu #10,d1 * shift left one decimal digit
and.w #$000F,d0 * make ASCII digit binary
add.w d0,d1 * add current digit
move.w d1,field(a6) * store answer
bra lp0pf * get next format char
sk1pf:
move.l #dispatch,a0 * get case table address for case
bra case * go do case select.
no_ctl:
move.w d0,-(a7) * push character
bsr putc * print it
addq.l #2,a7 * trash parameter
bra loop * do it again.
exit:
movem.l (a7)+,d0-d6/a0-a2
unlk a6
rts
*****************************************************************
d_arg:
move.w (a2)+,d0 * get value, move pointer
ext.l d0 * convert to common format
bsr sign * print sign, if any, take abs()
bra printdec * go print value
*****************************************************************
u_arg:
move.w (a2)+,d0 * get value, move pointer
and.l #$0000FFFF,d0 * zero out high word
bra printdec * go print value
*****************************************************************
D_arg:
move.l (a2)+,d0 * get value, move pointer
bsr sign * print sign, if any, take abs()
bra printdec * go print value
*****************************************************************
U_arg:
move.l (a2)+,d0 * get value, move pointer
bra printdec * print decimal value
*****************************************************************
* SIGN - print sign if needed and takes abs() of value
sign:
tst.l d0 * is it negative?
bpl sk0_sg * exit if not
move.w #-1,signf(a6) * flag sign needed
subq.w #1,field(a6) * take away one for sign
neg.l d0 * change the sign
sk0_sg:
rts
*****************************************************************
* printdec - common decimal output routine. Value in D0.
printdec:
clr.w d1 * output digit count
lp0_pd:
divu #10,d0 * divide number by 10
bvs o_flow * number too large
swap d0 * get remainder in d0.w
move.w d0,-(a7) * push digit
addq.w #1,d1 * bump digit count
clr.w d0 * get rid of remainder
swap d0 * put quotient into d0.w
tst.w d0 * zero means we're done
bne lp0_pd * jumps if not done.
move.w d1,d6 * used for field adjust
bsr prefix * do prefix spaces
subq.w #1,d1 * adjust loop index counter
lp2_pd:
add.w #$30,(a7) * make digit TOS into ASCII
bsr putc * output digit
addq.l #2,a7 * eat digit from TOS
dbra d1,lp2_pd * output all digits
bsr postfix * do postfix spaces
bra loop * exit to control parser
o_flow:
move.l #oflowstr,-(a7) * push control string address
bsr printf * print it
addq.l #4,a7 * adjust stack
bra loop * continue
oflowstr:
dc.w '*overflow*',0
*****************************************************************
* PREFIX - outputs prefix spaces and/or sign
prefix:
tst.w field(a6) * check if field nonzero
ble chksign * if zero, just boogie on out
tst.w leftj(a6) * left justify selected?
bne chksign * jump if no
sub.w d6,field(a6) * digits allowed - digits actual
ble chksign * exit if no spaces needed
lp0_pr:
move.w d0,-(a7) * save d0 across call to _put
move.w #' ',-(a7) * space to output
bsr putc * output the space
addq.l #2,a7 * adjust stack
move.w (a7)+,d0 * retrieve d0
subq.w #1,field(a6) * decrement loop index
bne lp0_pr * do again if more spaces needed
chksign:
tst.w signf(a6) * sign needed?
beq chkexit * jump if no
move.l d0,d2 * save d0 across call to _put
move.w #' -',-(a7) * push sign
bsr putc * output it
addq.l #2,a7 * adjust stack
move.l d2,d0 * retrieve argument
chkexit:
rts
*****************************************************************
* POSTFIX - prints postfix spaces in field
postfix:
sub.w d6,field(a6) * digits allowed - digits actual
ble sk1_po * exit if no spaces needed
lp0_po:
move.w #' ',-(a7) * space to output
bsr putc * output the space
addq.l #2,a7 * adjust stack
subq.w #1,field(a6) * decrement loop index
bne lp0_po * do again if more spaces needed
sk1_po:
rts
*****************************************************************
x_arg:
move.w #3,d1 * number of digits to print
move.w #4,d6 * used for field adjust
move.w (a2)+,d2 * transfer output value
swap d2 * position output value
bra printhex * go print it
*****************************************************************
X_arg:
move.w #7,d1 * number of digits to print
move.w #8,d6 * used for field adjust
move.l (a2)+,d2 * transfer output value
bra printhex * go print it
*****************************************************************
* PRINTHEX - outputs value held in D2 in hex. D1 is digit count
printhex:
bsr prefix * output prefix spaces
lp0ph:
move.l #hexdigits,a0 * address of translate table
rol.l #4,d2 * put MSD in low four bits
move.w d2,d0 * we're only interested in LSD
and.w #$000F,d0 * so we hack off all but LSD
move.b 0(a0,d0.w),d0 * get digit
move.w d0,-(a7) * push for output
bsr putc * output it
addq.l #2,a7 * trash parameter
dbra d1,lp0ph * loop for next digit
bsr postfix * do postfix spaces
bra loop * return to control string parser
hexdigits:
dc.w '0123456789ABCDEF'
*****************************************************************
s_arg:
move.l (a2),a0 * get string address from stack
clr.w d6 * get strlen for field adjust
slen:
tst.b (a0)+ * look for terminal null
beq sk0_sa * jump if found
addq.w #1,d6 * increment string length counter
bra slen * look at next byte
sk0_sa:
move.l (a2)+,a0 * get string address again
bsr prefix * print prefix spaces
lp0_sa:
tst.b (a0) * end of string?
bne sk1_sa * no, keep going
bsr postfix * print postfix spaces
bra loop * continue parsing format string
sk1_sa:
move.b (a0)+,d0 * get char from string
move.w d0,-(a7) * push for output
bsr putc * output it
addq.l #2,a7 * adjust stack
bra lp0_sa * continue
*****************************************************************
c_arg:
move.w (a2)+,-(a7) * get argument
bsr putc * send it out
addq.l #2,a7 * adjust stack
bra loop * continue
*****************************************************************
v_arg:
move.l (a2)+,-(a7) * move both args at once
bsr cursor * perform function
addq.l #4,a7 * adjust stack
bra loop * continue parse of control str
*****************************************************************
* DEFAULT: user has specified unknown control argument
default:
move.w d0,-(a7) * we'll just print it.
bsr putc * so there it goes!
addq.l #2,a7 * adjust stack
bra loop * that's all for here
*****************************************************************
* Case dispatch table for printf
dispatch:
dc.w 9 * number of valid options
dc.b 0,'d' * %d print signed decimal word
dc.l d_arg
dc.b 0,'u' * %u print unsigned decimal word
dc.l u_arg
dc.b 0,'D' * %D print signed decimal longword
dc.l D_arg
dc.b 0,'U' * %U print unsigned decimal longword
dc.l U_arg
dc.b 0,'x' * %x print hex word
dc.l x_arg
dc.b 0,'X' * %X print hex longword
dc.l X_arg
dc.b 0,'s' * %s print null terminated string
dc.l s_arg
dc.b 0,'c' * %c print character
dc.l c_arg
dc.b 0,'v' * %v set cursor (X,Y)
dc.l v_arg
dc.l default * all unknown cases handled here
end